/*
 * @Author: zhang_gen_yuan
 * @Date: 2020-12-18 13:26:51
 * @LastEditTime: 2020-12-21 09:56:16
 */

class Observer {
    constructor(data) {
        this.observe(data);
    }
    observe(data) {
        if (data && typeof data === 'object') {
            Object.keys(data).forEach(key => {
                this.defineReactive(data, key, data[key]);
            })
        }
    }
    defineReactive(obj, key, value) {
        this.observe(value);
        const dep = new Dep();
        Object.defineProperty(obj, key, {
            get: () => {
                Dep.target && dep.addSub(Dep.target)
                return value;
            },
            set: (newVal) => {
                if (newVal !== value) {
                    this.observe(newVal);
                    value = newVal;
                }
                dep.notify();
            }
        })
    }
}

// 发布者
class Dep {
    constructor() {
        this.subs = []
    }
    addSub(watcher) {
        this.subs.push(watcher);
    }
    notify() {
        this.subs.forEach(w=>w.update())
    }
}
// 订阅者
class Watcher {
    constructor(vm, expr, cb) {
        this.vm = vm;
        this.expr = expr;
        this.cb = cb;
        this.oldVal = this.getOldVal();
    }
    getOldVal() {
        Dep.target = this;
        let oldVal = compileDir.getVal(this.expr, this.vm);
        Dep.target = null;
        return oldVal;
    }

    update() {
        let newVal = compileDir.getVal(this.expr, this.vm);
        if (newVal != this.oldVal) {
            this.cb(newVal)
        }
    }
}



/*

    MVVM   module-view-viewModule  数据驱动视图
    Vue2.X 通过Object.defineProperty getter/setter劫持数据 , 结合发布者-订阅者模式实现数据双向绑定

    Observer类递归数据监听  get收集依赖   set触发依赖 执行Watcher类update方法 拿到新值与旧值作比较,不相等则执行回调函数 更新视图

*/ 